#include <cmath>
#include "app/ApplicationConfig.h"
#include "GUIEngine.h"
#include "util/exceptions/ElementNotFoundException.h"
#include "util/MathUtils.h"

namespace gui {

GUIEngine::GUIEngine(int width, int height, int bpp, std::string caption,
		bool fullScreen, int deltaX, int deltaY) {
	this->screenRect.w = width;
	this->screenRect.h = height;
	this->screenRect.x = 0;
	this->screenRect.y = 0;

	this->screenBPP = bpp;
	this->screenCaption = caption;
	this->fullScreen = fullScreen;
	this->imageCache = new ImageCache();
	this->xScale = 1;
	this->yScale = 1;
}

GUIEngine::~GUIEngine() {
	delete this->imageCache;
}

bool GUIEngine::start(int h, int w, bool splashScreen) {
	if (SDL_Init(SDL_INIT_VIDEO) == -1) {
		return false;
	}

	int defaults = SDL_HWSURFACE | SDL_DOUBLEBUF;

	this->screen = SDL_SetVideoMode(this->screenRect.w, this->screenRect.h, this->screenBPP,
			(this->fullScreen) ? defaults | SDL_FULLSCREEN : defaults);

	if (this->screen == NULL) {
		return false;
	}
    this->rColor = app::ApplicationConfig::getOptionalIntProperty("bgColorR", 242);
    this->gColor = app::ApplicationConfig::getOptionalIntProperty("bgColorG", 239);
    this->bColor = app::ApplicationConfig::getOptionalIntProperty("bgColorB", 233);
//    this->fillSurface(this->screen, this->rColor, this->gColor, this->bColor);

    if (splashScreen) this->showSplash();

//    this->mapSurface = SDL_CreateRGBSurface(SDL_HWSURFACE, w, h, this->screenBPP, 0, 0, 0, 0);
//    this->fillSurface(this->mapSurface, this->rColor, this->gColor, this->bColor);

    SDL_WM_SetCaption(this->screenCaption.c_str(), NULL);
	return true;
}

void GUIEngine::setScale(double xScale, double yScale) {
    this->xScale = xScale;
    this->yScale = yScale;
}

void GUIEngine::stop() {
	SDL_FreeSurface(this->screen);
	SDL_Quit();
}

void GUIEngine::drawSurface(Surface* surface){
	this->drawSurface(surface->getSurface(), NULL);
}

void GUIEngine::clearScreen() {
//	this->fillSurface(this->screen, this->rColor, this->gColor, this->bColor);
}

int GUIEngine::pollEvent(GUIEvent* event) {
	SDL_Event sdlEvent;
	int ret = SDL_PollEvent(&sdlEvent);
	if (ret) {
		event->fillEvent(sdlEvent);
	}
	return ret;
}

int GUIEngine::waitEvent(GUIEvent* event) {
	SDL_Event sdlEvent;
	int ret = SDL_WaitEvent(&sdlEvent);
	event->fillEvent(sdlEvent);
	return ret;
}

bool GUIEngine::getKeyState(GUIEventKey key) {
	Uint8* keyState = SDL_GetKeyState(NULL);
	return (bool) keyState[key];
}


SDL_Surface* GUIEngine::loadImage(std::string fileName, int transparentColorR,
		int transparentColorG, int transparentColorB) {
	SDL_Surface* aux = NULL;
	SDL_Surface* ret = NULL;
	aux = SDL_LoadBMP(fileName.c_str());
	if (aux != NULL) {
		ret = SDL_DisplayFormat(aux);
		SDL_FreeSurface(aux);
	}
	SDL_SetColorKey(ret, SDL_RLEACCEL | SDL_SRCCOLORKEY, SDL_MapRGB(ret->format, transparentColorR, transparentColorG, transparentColorB));
	return ret;
}
/*

SDL_Rect GUIEngine::getRectFromPortion(Portion portion) {
	SDL_Rect ret;
	ret.x = portion.x;
	ret.y = portion.y;
	ret.h = portion.h;
	ret.w = portion.w;
	return ret;
}
*/

void GUIEngine::refreshScreen() {
	SDL_Flip(this->screen);
}

void GUIEngine::drawSurface(SDL_Surface* surface, SDL_Rect* position) {
	SDL_BlitSurface(surface, NULL, this->screen, position);
	this->refreshScreen();
}

SDL_Surface* GUIEngine::copySurface(SDL_Surface* surface, int h, int w) {
	SDL_Surface* ret = createSurface(surface, h, w);
	SDL_BlitSurface(surface, NULL, ret, NULL);
	return ret;
}

SDL_Surface* GUIEngine::createSurface(SDL_Surface* surface, int h, int w) {
	SDL_Surface* ret = NULL;
	ret = SDL_CreateRGBSurface(SDL_HWSURFACE, w, h,
				surface->format->BitsPerPixel, surface->format->Rmask,
				surface->format->Gmask, surface->format->Bmask, surface->format->Amask);
	return ret;
}


void GUIEngine::showSplash() {
	SDL_Surface* splash = SDL_LoadBMP("res/img/splash.bmp");
	SDL_SetColorKey(splash, SDL_RLEACCEL | SDL_SRCCOLORKEY, SDL_MapRGB(splash->format, 255, 255, 255));
	SDL_Rect pos;
	pos.x = util::doubleToInt((this->screen->w - splash->w) / 2.0);
	pos.y = util::doubleToInt((this->screen->h - splash->h) / 2.0);
	this->drawSurface(splash, &pos);
	SDL_FreeSurface(splash);
}
/*

void GUIEngine::resizePortion(Portion* portion){
	portion->w = util::doubleToInt(portion->w * this->xScale);
	portion->x = util::doubleToInt(portion->x * this->xScale);
	portion->h = util::doubleToInt(portion->h * this->yScale);
	portion->y = util::doubleToInt(portion->y * this->yScale);

}
*/
/*

void GUIEngine::drawPortion(Portion portion) {
   // transformo la dimension del portion segun la escala en la que se muestra la misma
   this->resizePortion(&portion);
   SDL_Rect rect = this->getRectFromPortion(portion);
//   SDL_Surface* aux = this->copySurface(this->mapSurface, portion.h, portion.w);
   // TODO: Remplazar harcode
   // SDL_Surface* aux = this->copySurface(this->mapSurface, this->mapSurface->h, this->mapSurface->w);
   //this->fillSurface(aux, this->rColor, this->gColor, this->bColor);
   // SDL_BlitSurface(this->mapSurface, &rect, aux, &rect);
//   SDL_BlitSurface(this->mapSurface, NULL, aux, &rect);
//   SDL_SetColorKey(aux, SDL_RLEACCEL | SDL_SRCCOLORKEY, this->mapSurface->format->colorkey);
   SDL_Rect rectAux;
   rectAux.x = -rect.x;
   rectAux.y = -rect.y;
   this->clearScreen();
//this->drawSurface(aux, &rectAux);
//   SDL_FreeSurface(aux);
}
*/

}
